/*
实验内容3：生产者-消费者问题
实验要求：
利用所学的 Windows 系统调用，创建线程、线程同步、线程互斥等，实现具有 N 个缓
冲区的生产者-消费者问题。算法可参考 Fig.4.13, Bounded-Buffer Producer/Consumer Problem
Using Semaphores.
*/

#define _CRT_SECURE_NO_WARNINGS

#include <windows.h>
#include <stdio.h>

#define BUFFER_SIZE 5

// 缓冲区
int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;

// 信号量和互斥对象句柄
HANDLE emptySemaphore;
HANDLE fullSemaphore;
HANDLE mutex;

// 生产者线程函数
DWORD WINAPI Producer(LPVOID lpParam) {
    int producerId = (int)(intptr_t)lpParam;
    for (int i = 0; i < 5; ++i) {
        // 生产一个项目
        int item = rand() % 100; // 随机生成一个物品

        // 等待空位
        WaitForSingleObject(emptySemaphore, INFINITE);

        // 进入临界区
        WaitForSingleObject(mutex, INFINITE);

        // 将项目放入缓冲区
        buffer[in] = item;
        printf("生产者%d将物品%d放入缓冲区[%d]\n", producerId, item, in);
        in = (in + 1) % BUFFER_SIZE;

        // 退出临界区
        ReleaseMutex(mutex);

        // 增加满位计数
        ReleaseSemaphore(fullSemaphore, 1, NULL);

        Sleep(100); // 模拟生产时间
    }
    return 0;
}

// 消费者线程函数
DWORD WINAPI Consumer(LPVOID lpParam) {
    int consumerId = (int)(intptr_t)lpParam;
    for (int i = 0; i < 3; ++i) {
        // 等待满位
        WaitForSingleObject(fullSemaphore, INFINITE);

        // 进入临界区
        WaitForSingleObject(mutex, INFINITE);

        // 从缓冲区取出项目
        int item = buffer[out];
        printf("消费者%d从缓冲区[%d]取出物品%d\n", consumerId, out, item);
        out = (out + 1) % BUFFER_SIZE;

        // 退出临界区
        ReleaseMutex(mutex);

        // 增加空位计数
        ReleaseSemaphore(emptySemaphore, 1, NULL);

        Sleep(150); // 模拟消费时间
    }
    return 0;
}

int main() {
    HANDLE producerThreads[2];
    HANDLE consumerThreads[3];
    DWORD producerThreadIds[2];
    DWORD consumerThreadIds[3];

    // 初始化随机数生成器
    srand(GetTickCount());

    // 创建信号量和互斥对象
    emptySemaphore = CreateSemaphore(NULL, BUFFER_SIZE, BUFFER_SIZE, TEXT("EmptySemaphore"));
    if (emptySemaphore == NULL) {
        printf("创建空位信号量失败: %d\n", GetLastError());
        return 1;
    }

    fullSemaphore = CreateSemaphore(NULL, 0, BUFFER_SIZE, TEXT("FullSemaphore"));
    if (fullSemaphore == NULL) {
        printf("创建满位信号量失败: %d\n", GetLastError());
        CloseHandle(emptySemaphore);
        return 1;
    }

    mutex = CreateMutex(NULL, FALSE, TEXT("Mutex"));
    if (mutex == NULL) {
        printf("创建互斥对象失败: %d\n", GetLastError());
        CloseHandle(emptySemaphore);
        CloseHandle(fullSemaphore);
        return 1;
    }

    // 创建两个生产者线程
    for (int i = 0; i < 2; ++i) {
        producerThreads[i] = CreateThread(
            NULL,                   // 默认安全属性
            0,                      // 使用默认堆栈大小  
            Producer,               // 线程函数名称
            (LPVOID)(intptr_t)(i + 1), // 参数传入线程函数
            0,                      // 立即运行线程 
            &producerThreadIds[i]); // 返回线程标识符

        if (producerThreads[i] == NULL) {
            printf("创建生产者线程失败: %d\n", GetLastError());
            CloseHandle(emptySemaphore);
            CloseHandle(fullSemaphore);
            CloseHandle(mutex);
            for (int j = 0; j < i; ++j) {
                CloseHandle(producerThreads[j]);
            }
            return 1;
        }
    }

    // 创建三个消费者线程
    for (int i = 0; i < 3; ++i) {
        consumerThreads[i] = CreateThread(
            NULL,                   // 默认安全属性
            0,                      // 使用默认堆栈大小  
            Consumer,               // 线程函数名称
            (LPVOID)(intptr_t)(i + 1), // 参数传入线程函数
            0,                      // 立即运行线程 
            &consumerThreadIds[i]); // 返回线程标识符

        if (consumerThreads[i] == NULL) {
            printf("创建消费者线程失败: %d\n", GetLastError());
            CloseHandle(emptySemaphore);
            CloseHandle(fullSemaphore);
            CloseHandle(mutex);
            for (int j = 0; j < 2; ++j) {
                CloseHandle(producerThreads[j]);
            }
            for (int j = 0; j < i; ++j) {
                CloseHandle(consumerThreads[j]);
            }
            return 1;
        }
    }

    // 等待所有线程完成
    for (int i = 0; i < 2; ++i) {
        WaitForSingleObject(producerThreads[i], INFINITE);
    }
    for (int i = 0; i < 3; ++i) {
        WaitForSingleObject(consumerThreads[i], INFINITE);
    }

    // 关闭线程句柄
    for (int i = 0; i < 2; ++i) {
        CloseHandle(producerThreads[i]);
    }
    for (int i = 0; i < 3; ++i) {
        CloseHandle(consumerThreads[i]);
    }

    // 关闭信号量和互斥对象句柄
    CloseHandle(emptySemaphore);
    CloseHandle(fullSemaphore);
    CloseHandle(mutex);

    printf("生产者-消费者问题结束\n");

    return 0;
}



